﻿using Letter.IO.Binary;
using System;
using System.Buffers;
using System.Net;
using System.Threading.Tasks;
using eTask.Extensions;

namespace Letter.Net.Udp;

public abstract class AUdpConnection : AConnection
{
    private Task receiveTask;
    
    
    public override void OnActive()
    {
        this.receiveTask = this.StartReadAsync();
    }

    private async Task StartReadAsync()
    {
        var input = base.Transport.Reader;
        while(true)
        {
            var result = await input.ReadAsync();
            if(result.IsCanceled || result.IsCompleted)
            {
                break;
            }

            var buf = result.Buffer;
            this.OnMessage((EndPoint)input.Token, ref buf);
            input.AdvanceTo(result.Buffer.End);
            input.Flush();
        }
        
        await input.CompleteAsync();
    }

    protected abstract void OnMessage(EndPoint remoteEP, ref ReadOnlySequence<byte> buf);


    public void WriteAndPushAsync(ref ReadOnlySequence<byte> buf)
    {
        this.WriteAndPushAsync(null, ref buf);
    }

    public void WriteAndPushAsync(EndPoint target, ref ReadOnlySequence<byte> buf)
    {
        if (!this.Active)
        {
            return;
        }
        
        if (buf.Length == 0)
        {
            throw new ArgumentNullException(nameof(buf));
        }

        var output = this.Transport.Writer;
        var writer = output.ToBytesWriter();
        writer.WriteSequence(ref buf);
        output.Token = target;
        output.FlushAsync().Ignore();
    }

    public override void OnException(Exception ex)
    {
        
    }

    public override void OnInactive()
    {
        if (this.receiveTask != null)
        {
            this.receiveTask.GetAwaiter().GetResult();
        }
    }
}
